#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "symbol.h"

int Hash(char *str) {
	unsigned hash = 0;
	/* loop over the entire string */
	while (*str != 0) {
		/* add the ascii value of the sign to the sum*/
		hash = hash + (int) *str;
		/* move pointer to next and check if its 0 */
		str++;
		if (*str != 0) {
			/* if not then shift */
			hash = hash << 1;
		}
	}
	return (hash % HashSize);
}
SymbolTable *initSymbolTable() {
	/* a table is created. */
	SymbolTable *tmp = NEW(SymbolTable);
	int i;
	for(i = 0; i < HashSize; i++) {
		tmp->table[i] = NULL;
	}
	tmp->next = NULL;
	return tmp;
}
SymbolTable *scopeSymbolTable(SymbolTable *t) {
	/* a table is created using the method above. */
	SymbolTable *new = initSymbolTable();
	/* the pointer in next is set to point to the table given as input */
	new->next = t;
	return new;
}
SYMBOL *putSymbolType(SymbolTable *t, char *name, TYPE *type) {
	/* find the bucket in the table where the SYMBOL should be stored */
	int bucket = Hash(name);
	SYMBOL *new = NEW(SYMBOL);
	SYMBOL *tmp;
	new->name = malloc(strlen(name));
	strcpy(new->name, name);
	new->kind = typeSK;
	new->val.type = type;
	if (t->table[bucket] == NULL) { // edited
		/* if the bucket is empty then use the bucket with a new SYMBOL */
		t->table[bucket] = new;
		return new;
	} else {
		tmp = t->table[bucket];
		if (strcmp(tmp->name, name) == 0) {
			/* If a duplicate exists */
			return NULL;
		}
		/* else find the next empty in the chain of symbols */
		while (tmp->next != NULL) {
			/* if the name exists then return null */
			tmp = tmp->next;
			if (strcmp(tmp->name, name) == 0) {
				/* If duplicate exists */
				return NULL;
			}
		}
		/* if empty symbol is found then use it and set the
		 next-pointer of the previous symbol to this symbol */
		tmp->next = new;
		return new;
	}
}
SYMBOL *putSymbolFunction(SymbolTable *t, char *name, FUNCTION *function) {
	/* find the bucket in the table where the SYMBOL should be stored */
	int bucket = Hash(name);
	SYMBOL *new = NEW(SYMBOL);
	SYMBOL *tmp;
	new->name = malloc(strlen(name));
	strcpy(new->name, name);
	new->kind = functionSK;
	new->val.function = function;
	if (t->table[bucket] == NULL) { // edited
		/* if the bucket is empty then use the bucket with a new SYMBOL */
		t->table[bucket] = new;
		return new;
	} else {
		tmp = t->table[bucket];
		if (strcmp(tmp->name, name) == 0) {
			/* If a duplicate exists */
			//printf("putSymbol: (%s, %d) trying to insert duplicate... Not allowed \n",name,value);
			return NULL;
		}
		/* else find the next empty in the chain of symbols */
		while (tmp->next != NULL) {
			/* if the name exists then return null */
			tmp = tmp->next;
			if (strcmp(tmp->name, name) == 0) {
				/* If duplicate exists */
				//printf("putSymbol: (%s, %d) trying to insert duplicate... Not allowed \n",name,value);
				return NULL;
			}
		}
		/* if empty symbol is found then use it and set the
		 next-pointer of the previous symbol to this symbol */
		tmp->next = new;
		return new;
	}
}
SYMBOL *putSymbolVariable(SymbolTable *t, char *name, VAR_TYPE *var_type) {
	/* find the bucket in the table where the SYMBOL should be stored */
	int bucket = Hash(name);
	SYMBOL *new = NEW(SYMBOL);
	SYMBOL *tmp;
	new->name = malloc(strlen(name));
	strcpy(new->name, name);
	new->kind = variableSK;
	new->val.var_type = var_type;
	if (t->table[bucket] == NULL) { // edited
		/* if the bucket is empty then use the bucket with a new SYMBOL */
		t->table[bucket] = new;
		return new;
	} else {
		tmp = t->table[bucket];
		if (strcmp(tmp->name, name) == 0) {
			/* If a duplicate exists */
			//printf("putSymbol: (%s, %d) trying to insert duplicate... Not allowed \n",name,value);
			return NULL;
		}
		/* else find the next empty in the chain of symbols */
		while (tmp->next != NULL) {
			/* if the name exists then return null */
			tmp = tmp->next;
			if (strcmp(tmp->name, name) == 0) {
				/* If duplicate exists */
				//printf("putSymbol: (%s, %d) trying to insert duplicate... Not allowed \n",name,value);
				return NULL;
			}
		}
		/* if empty symbol is found then use it and set the
		 next-pointer of the previous symbol to this symbol */
		tmp->next = new;
		return new;
	}
}
SYMBOL *getSymbol(SymbolTable *t, char *name) {
	/* find where the name's bucket is*/
	int index = Hash(name);
	if (t->table[index] != NULL) {
		/* if a symbol exists */
		SYMBOL *symbol = t->table[index];
		while (strcmp(symbol->name, name) != 0 && symbol->next != NULL) {
			symbol = symbol->next;
		}
		if (strcmp(symbol->name, name) == 0) {
			return symbol;
		} else {
			if (t->next != NULL) {
				return getSymbol(t->next, name);
			} else {
				return NULL;
			}
		}
	} else {
		/* if there is nothing in the bucket */
		if (t->next != NULL) {
			return getSymbol(t->next, name);
		} else {
			return NULL;
		}
	}
}
void dumpSymbolTable(SymbolTable *t) {
	SYMBOL *current;
	int tmp = 0;
	fprintf(stderr,"dumpSymbolTable:\n");
	do {
		/* if this is not the first runthrough then go to next table */
		if (tmp > 0) {
			t = t->next;
		}
		/* run through the entire table */
		int i;
		for (i = 0; i < HashSize; i++) {
			if (t->table[i] != NULL) {
				current = t->table[i];
				if(current->kind==typeSK){
					fprintf(stderr,"Type: %s in bucket %d \n", current->name, i);
				}
				if(current->kind==functionSK){
					fprintf(stderr,"Function: %s in bucket %d \n", current->name, i);
				}
				if(current->kind==variableSK){
					fprintf(stderr,"Variable: %s in bucket %d \n", current->name, i);
				}
				while (current->next != NULL) {
					current = current->next;
					if(current->kind==typeSK){
						fprintf(stderr,"Type: %s in bucket %d \n", current->name, i);
					}
					if(current->kind==functionSK){
						fprintf(stderr,"Function: %s in bucket %d \n", current->name, i);
					}
					if(current->kind==variableSK){
						fprintf(stderr,"Variable: %s in bucket %d \n", current->name, i);
					}
				}
			}
		}
		tmp++;
	} while (t->next != NULL);
}
